//
//  NSDictionary+CLCategory.m
//  CLBrowser
//
//  Created by 梁慧聪 on 2021/7/9.
//

#import "NSDictionary+CLCategory.h"
#import <objc/runtime.h>
#import "NSObject+CLSwizzling.h"
@implementation NSDictionary (CLCategory)

#pragma mark *** Instance Method ***
- (id)cl_objectForKey:(NSString *)key {
    // key
    if ([key isKindOfClass:[NSNull class]] ||
        ([key isKindOfClass:[NSString class]] == NO) ||
        (key.length == 0)) {
        return nil;
    }
    // value
    id relust = [self objectForKey:key];
    if ([relust isKindOfClass:[NSNull class]]) {
        return nil;
    }
    return relust;
}

- (id)cl_objectForKey:(NSString *)key defaultValue:(id)value {
    // relust
    id relust = [self cl_objectForKey:key];
    if (relust != nil) {
        return relust;
    }
    // defaultValue
    if (value != nil) {
        relust = value;
    }
    return relust;
}

- (NSString *)cl_toJsonString {
    
    NSError *error;
    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:self
                                                       options:kNilOptions
                                                         error:&error];
    if (jsonData == nil) {
        return nil;
    }
    return [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
}


#pragma mark *** Class Method ***

+ (instancetype)cl_dictionaryWithJSONString:(NSString *)JSONString {
    // JSONString
    if ([JSONString isKindOfClass:[NSNull class]] ||
        ([JSONString isKindOfClass:[NSString class]] == NO) ||
        (JSONString.length == 0)) {
        return nil;
    }
    
    // dictionary
    NSData *JSONData = [JSONString dataUsingEncoding:NSUTF8StringEncoding];
    NSError *error = NULL;
    NSDictionary *relust = [NSJSONSerialization JSONObjectWithData:JSONData
                                                           options:NSJSONReadingMutableContainers
                                                             error:&error];
    if (error) { return nil; }
    return relust;
}



- (NSArray *)cl_arrayForKey:(NSString *)key
{
    return [self _zj_objectForKey:key verifyClass:[NSArray class]];
}

- (NSDictionary *)cl_dictionaryForKey:(NSString *)key
{
    return [self _zj_objectForKey:key verifyClass:[NSDictionary class]];
}

- (NSString *)cl_stringForKey:(NSString *)key
{
    return [self _zj_objectForKey:key verifyClass:[NSString class]];
}

- (NSNumber *)cl_numberForKey:(NSString *)key
{
    id object = [self objectForKey:key];
    if ([object isKindOfClass:[NSString class]])
    {
        return [self stringToNumber:object];
    }else
    {
        return [self _zj_objectForKey:key verifyClass:[NSNumber class]];
    }
    
}
-(NSDate*) cl_dateForKey:(NSString*) key andFormat:(NSString*) format
{
    id obj = [self objectForKey:key];
    if (obj==nil)
    {
        return [NSDate dateWithTimeIntervalSince1970:0];
    }
    if ([format length]==0)
    {
        return [NSDate dateWithTimeIntervalSince1970:0];
    }
    if ([obj isKindOfClass:[NSDate class]])
    {
        return obj;
    }
    else if([obj isKindOfClass:[NSString class]])
    {
        NSDateFormatter * dateFormatter = [[NSDateFormatter alloc] init];
        [dateFormatter setDateFormat:format];
        if (obj != nil)  {
            NSDate*curDate = [dateFormatter dateFromString:obj];
            //        [date release];
            if (curDate!=nil)
            {
                return curDate;
            }
        }
    }
    return [NSDate dateWithTimeIntervalSince1970:0];
    
}
#pragma mark - Private

- (id)_zj_objectForKey:(NSString *)key verifyClass:(__unsafe_unretained Class)aClass
{
    id object = [self objectForKey:key];
    if ([object isKindOfClass:aClass]) {
        return object;
    }
    else if([object isKindOfClass:[NSString class]] && [aClass isSubclassOfClass:[NSNumber class]])
    {
        //如果要求的是NSNumber，传递过来的值是NSString. 做特殊转换
        return [NSNumber numberWithInt:[object intValue]];
    }
    else if ([object isKindOfClass:[NSNumber class]] && [aClass isSubclassOfClass:[NSString class]])
    {
        return [NSString stringWithFormat:@"%d", [object intValue]];
    }
    
    return [aClass new];
}
- (NSNumber*) stringToNumber:(NSString*) str{
    if (str==nil) {
        return [NSNumber numberWithInt:0];
    }
    NSString*value = str;
    if (![str isKindOfClass:[NSString class]]) {
        value = [str description];
    }
    if ([value isEqualToString:@""]) {
        return [NSNumber numberWithInt:0];
    }else{
        NSNumberFormatter * f = [[NSNumberFormatter alloc] init];
        [f setNumberStyle:NSNumberFormatterDecimalStyle];
        NSNumber * myNumber = [f numberFromString:value];
        //        [f release];
        return myNumber;
    }
    
}
@end
@implementation NSMutableDictionary (Category)

+ (void)load {
    //只执行一次这个方法
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        
        // 替换 removeObjectForKey:
        NSString *tmpRemoveStr = @"removeObjectForKey:";
        NSString *tmpSafeRemoveStr = @"safeMutable_removeObjectForKey:";
        
        [NSObject exchangeInstanceMethodWithSelfClass:NSClassFromString(@"__NSDictionaryM")
                                     originalSelector:NSSelectorFromString(tmpRemoveStr)                                     swizzledSelector:NSSelectorFromString(tmpSafeRemoveStr)];
        
        
        
        // 替换 setObject:forKey:
        NSString *tmpSetStr = @"setObject:forKey:";
        NSString *tmpSafeSetRemoveStr = @"safeMutable_setObject:forKey:";
        
        [NSObject exchangeInstanceMethodWithSelfClass:NSClassFromString(@"__NSDictionaryM")
                                     originalSelector:NSSelectorFromString(tmpSetStr)                                     swizzledSelector:NSSelectorFromString(tmpSafeSetRemoveStr)];
        
    });
    
}

#pragma mark --- implement method

/**
 根据akey 移除 对应的 键值对
 
 @param aKey key
 */
- (void)safeMutable_removeObjectForKey:(id<NSCopying>)aKey {
    if (!aKey) {
        return;
    }
    [self safeMutable_removeObjectForKey:aKey];
}

/**
 将键值对 添加 到 NSMutableDictionary 内
 
 @param anObject 值
 @param aKey 键
 */
- (void)safeMutable_setObject:(id)anObject forKey:(id<NSCopying>)aKey {
    if (!anObject) {
        return;
    }
    if (!aKey) {
        return;
    }
    return [self safeMutable_setObject:anObject forKey:aKey];
}

- (void)cl_setObjectSafe:(id)anObject forKey:(id<NSCopying>)aKey {
    
    if (!aKey) {
        NSLog(@"nil aKey:%@,%@",aKey,NSStringFromSelector(_cmd));
        return;
    }
    if (!anObject){
        NSLog(@"nil aKey:%@,%@",aKey,NSStringFromSelector(_cmd));
        return;
    }
    
    return [self setObject:anObject forKey:aKey];
}

@end
